#!/usr/bin/env drgn

from drgn.helpers.linux.pid import for_each_task
from drgn.helpers.linux.percpu import per_cpu
from drgn import Object
from drgn.helpers.linux.printk import get_dmesg
import time
import datetime

def get_sys_info():

    print('System Information:')
    print()
    uts_namespace = prog['init_uts_ns']
    node_name = uts_namespace.name.nodename.string_().decode('utf-8')
    version = uts_namespace.name.version.string_().decode('utf-8')
    release = uts_namespace.name.release.string_().decode('utf-8')
    machine = uts_namespace.name.machine.string_().decode('utf-8')
    print('{:>15}: {}'.format('NODENMAE', node_name))
    print('{:>15}: {}'.format('RELEASE', release))
    print('{:>15}: {}'.format('VERSION', version))
    print('{:>15}: {}'.format('MACHINE', machine))

    timerkeeper = prog['shadow_timekeeper']
    xtime_sec = timerkeeper.xtime_sec
    ktime_sec = timerkeeper.ktime_sec
    date = time.ctime(xtime_sec)
    uptime = str(datetime.timedelta(seconds=int(ktime_sec)))
    print('{:>15}: {}'.format('DATE', date))
    print('{:>15}: {}'.format('UPTIME', uptime))
    print('{:>15}: {}'.format('LOAD AVERAGE', load_avg(prog['avenrun'])))
    cpus = int(prog['nr_cpu_ids'])
    try:
        total_pages = prog['_totalram_pages']
    except KeyError:
        total_pages = prog['totalram_pages']
    pages = Object(prog, 'int', address=total_pages.address_of_())
    page_size = int(prog['PAGE_SIZE'])
    memory_GB= float(pages.value_() * page_size / 1024 / 1024 / 1024)
    print('{:>15}: {}'.format('CPUS', cpus))
    print('{:>15}: {:0.2f} GB'.format('MEMORY', memory_GB))
    cpu = prog['crashing_cpu'].value_()
    task = per_cpu(prog['runqueues'], cpu).curr
    comm = task.comm.string_().decode('utf-8')
    pid = task.pid.value_()
    task_ptr = hex(task.value_())
    print('{:>15}: {}'.format('PID', pid))
    print('{:>15}: {}'.format('COMMAND', comm))
    print('{:>15}: {}'.format('TASK', task_ptr))
    print('{:>15}: {}'.format('CPU', cpu))
    print('')

def print_stacktrace(task):
    trace = prog.stack_trace(task)
    print(trace)

def load(a):
    fixed_1 = 1 << 11
    ans = a >> 11
    f_part = ((a & (fixed_1 - 1)) * 100) >> 11
    ans += float(f_part) / 100
    return ans

def load_avg(avenrun):
    fixed_1 = 1 << 11
    add = int(fixed_1 / 200)
    a = avenrun[0] + add
    b = avenrun[1] + add
    c = avenrun[2] + add
    ret = '{:0.2f}, {:0.2f}, {:0.2f}'.format(float(load(a)), float(load(b)), float(load(c)))
    return ret

def print_log():
    log = get_dmesg(prog).decode(errors="replace")
    print()
    print('dmesg log')
    print(log)

def main():

    get_sys_info()

    task = per_cpu(prog['runqueues'], prog['crashing_cpu']).curr
    pid = task.pid.value_()
    addr = hex(task)
    try:
        cpu = task.thread_info.cpu.value_()
    except AttributeError:
        cpu = task.cpu.value_()
    comm = task.comm.string_().decode('utf-8')
    print(f'Backtrace:')
    print(f'PID: {pid} TASK: {addr} CPU: {cpu} COMMAND: {comm}')
    print()
    print_stacktrace(task)

    #print_log()

if __name__ == '__main__':
    main()
